package com.bocloud.cmp.service.resource;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.CloudVendorDao;
import com.bocloud.cmp.dao.RegionDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.dao.VolumeDao;
import com.bocloud.cmp.driver.providers.intf.VolumeProvider;
import com.bocloud.cmp.entity.resource.CloudVendor;
import com.bocloud.cmp.entity.resource.Region;
import com.bocloud.cmp.entity.resource.Snapshot;
import com.bocloud.cmp.entity.resource.Volume;
import com.bocloud.cmp.enums.VMStatus;
import com.bocloud.cmp.enums.VendorType;
import com.bocloud.cmp.interfaces.resource.VolumeService;
import com.bocloud.cmp.model.VolBean;
import com.bocloud.cmp.model.VolumeBean;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.utils.ResourceEventPublisher;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.google.common.collect.Maps;

/**
 * 块设备Service接口实现
 * 
 * @author dongkai
 *
 */
@Service("volumeService")
public class VolumeServiceImpl implements VolumeService {

	private static Logger logger = LoggerFactory.getLogger(ImageServiceImpl.class);
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private VolumeDao volumeDao;
	@Autowired
	private CloudVendorDao cloudVendorDao;
	@Autowired
	private RegionDao regionDao;
	@Autowired
	private SnapshotDao snapshotDao;
	@Autowired
	private VolumeProvider volumeProvider;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		List<Volume> list = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			if (null == sorter) {
				sorter = Maps.newHashMap();
			}
			sorter.put("gmtCreate", Common.ONE);
			total = volumeDao.count(params);
			if (simple) {
				beans = volumeDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = volumeDao.list(page, rows, params, sorter);
				for (Volume volume : list) {
					Region region = regionDao.query(volume.getRegion());
					CloudVendor cloudVendor = cloudVendorDao.query(volume.getVendorId());
					if (null != region && null != cloudVendor) {
						volume.setRegionName(region.getName());
						volume.setVendorName(cloudVendor.getName());
					}
				}
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BsmResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list volume failure:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
	}

	@Override
	public BsmResult create(String params, Long userId) {
		JSONObject object = JSONTools.isJSONObj(params);
		Long id = object.getLong(Common.ID);
		Long region = object.getLong(Common.REGION);
		String name = object.getString(Common.NAME);
		Integer size = object.getInteger("size");
		String remark = object.getString("remark");
		// 云供应商
		CloudVendor cloudVendor = null;
		Region reg = null;
		try {
			cloudVendor = cloudVendorDao.query(id);
			reg = regionDao.query(region);
			if (null == cloudVendor || null == reg) {
				logger.error("get cloudVendor and region failure!");
				return new BsmResult(false, "创建失败!");
			}
		} catch (Exception e) {
			logger.error("get cloudvendor and reg error:", e);
			return new BsmResult(false, "创建失败!");
		}
		BsmResult bsmResult = null;
		VendorType type = VendorType.valueOf(cloudVendor.getType());
		Map<String, Object> param = MapTools.simpleMap("name", name);
		param.put("size", size);
		param.put("remark", remark);
		VolumeModel model = null;
		switch (type) {
		case OPENSTACK:
			model = JSONObject.parseObject(JSONObject.toJSONString(param), VolumeModel.class);
			bsmResult = this.create(cloudVendor.getUuid(), null, id, region, userId, model, type);
			break;
		case JDYUN:
			param.put("category", object.getString("category"));
			param.put("count", object.getInteger("count"));
			model = JSONObject.parseObject(JSONObject.toJSONString(param), VolumeModel.class);
			bsmResult = this.create(cloudVendor.getUuid(), reg.getCode(), id, region, userId, model, type);
			break;
		case ALIYUN:
			param.put("category", object.getString("category"));
			param.put("count", object.getInteger("count"));
			param.put("zone", object.getString("zone"));
			model = JSONObject.parseObject(JSONObject.toJSONString(param), VolumeModel.class);
			bsmResult = this.create(cloudVendor.getUuid(), reg.getCode(), id, region, userId, model, type);
			break;
		default:
			break;
		}
		return bsmResult;
	}

	/**
	 * 云硬盘创建
	 * 
	 * @param paramsMap
	 * @param vendorId
	 * @param region
	 * @param userId
	 * @return
	 */
	private BsmResult create(String vendor, String code, Long vendorId, Long region, Long userId, VolumeModel model,
			VendorType type) {
		BsmResult result = null;
		try {
			BsmResult bsmResult = volumeProvider.create(vendor, code, model);
			if (!bsmResult.isSuccess()) {
				return new BsmResult(false, bsmResult.getMessage());
			}
			Volume volume = JSONObject.parseObject(JSONObject.toJSONString(bsmResult.getData()), Volume.class);
			String status = volume.getStatus();
			volume.setVendorId(vendorId);
			volume.setStatus(VMStatus.BUILDING.name());
			volume.setRegion(region);
			volume.setCreaterId(userId);
			volumeDao.save(volume);
			result = new BsmResult(true, "创建任务已下发，正在执行...");
			String volumeId = volume.getVolumeId();
			// 开启一个线程更新状态
			new Thread(new Runnable() {
				@Override
				public void run() {
					Date start = new Date();
					boolean running = true;
					String operate = type.name().toLowerCase() + ".volume";
					while (running) {
						BsmResult bsmResult = volumeProvider.detail(volumeId, vendor, code);
						Date end = new Date();
						if (end.getTime() - start.getTime() > 1000 * 60 * 5) {
							volume.setStatus(VMStatus.EXCEPTION.name());
							running = false;
						}
						if (bsmResult.isSuccess()) {
							VolumeBean bean = JSONObject.parseObject(JSONObject.toJSONString(bsmResult.getData()),
									VolumeBean.class);
							if (!volumeId.equals(bean.getVolumeId())) {
								continue;
							}
							String state = bean.getStatus().toUpperCase();
							if (state.equals(status)) {
								try {
									Thread.sleep(3000);
								} catch (Exception e) {
									logger.error("thread sleep failure:", e);
								}
								continue;
							}
							try {
								volume.setStatus(state);
								volumeDao.update(volume);
								running = false;
								resourceEventPublisher
										.send(new OperateResult(bsmResult.isSuccess(), "新增云硬盘成功!", operate));
							} catch (Exception e) {
								logger.error("update status failure:", e);
								resourceEventPublisher.send(new OperateResult(false, "新增云硬盘失败!", operate));
							}
						}
					}
				}
			}).start();
		} catch (Exception e) {
			logger.error("create failure:", e);
			result = new BsmResult(false, "创建失败!");
		}
		return result;
	}

	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = Volume.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		Boolean result = false;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			Volume volume = volumeDao.query(id);
			if (null == volume) {
				logger.warn("volume data not exist");
				return new BsmResult(false, "数据不存在", "", "");
			}
			if (volume.getStatus().equals("IN_USE")) {
				return new BsmResult(false, "正在使用的云硬盘无法删除!");
			}
			// 判断是否存在快照
			List<Snapshot> snapshots = snapshotDao.listByVloumeId(volume.getVolumeId());
			if (!snapshots.isEmpty()) {
				return new BsmResult(false, "云硬盘存在快照无法删除!");
			}
			// 云供应商
			CloudVendor cloudVendor = cloudVendorDao.query(volume.getVendorId());
			// Region region = regionDao.query(volume.getRegion());
			if (null == cloudVendor) {
				logger.error("get cloudVendor failure");
				return new BsmResult(false, "删除失败", "", "");
			}
			BsmResult bsmResult = volumeProvider.remove(volume.getVolumeId(), cloudVendor.getUuid(), null);
			if (null == bsmResult || !bsmResult.isSuccess()) {
				return new BsmResult(false, "删除失败");
			}
			result = volumeDao.remove(id, userId);
		} catch (Exception e) {
			logger.error("remove volume fail:", e);
			return new BsmResult(false, "删除失败", "", "");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
		return result ? new BsmResult(true, "删除成功") : new BsmResult(false, "删除失败", "", "");
	}

	@Override
	public BsmResult detail(Long id) {
		try {
			Volume volume = volumeDao.query(id);
			CloudVendor cloudVendor = cloudVendorDao.query(volume.getVendorId());
			if (null != cloudVendor) {
				volume.setVendorName(cloudVendor.getName());
			}
			return new BsmResult(true, volume, "查询详情成功");
		} catch (Exception e) {
			logger.error("query volume detail fail:", e);
			return new BsmResult(false, "查询详情失败", "", "");
		}
	}

	@Override
	public BsmResult modify(VolBean bean, Long userId) {
		String path = Volume.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			Volume volume = volumeDao.query(bean.getId());
			if (null == volume) {
				logger.warn("volume does not exist!");
				return new BsmResult(false, "数据不存在!");
			}
			if (volume.getStatus().equals("IN_USE")) {
				return new BsmResult(false, "正在使用的云硬盘无法修改!");
			}
			CloudVendor cloudVendor = cloudVendorDao.query(volume.getVendorId());
			if (null == cloudVendor) {
				logger.error("get cloudVendor failure");
				return new BsmResult(false, "修改失败");
			}
			BeanUtils.copyProperties(bean, volume);
			BsmResult bsmResult = volumeProvider.modify(cloudVendor.getUuid(), null,
					JSONObject.parseObject(JSONObject.toJSONString(volume), VolumeModel.class));
			if (null == bsmResult || !bsmResult.isSuccess()) {
				return new BsmResult(false, "修改失败");
			}
			volume.setMenderId(userId);
			volumeDao.update(volume);
			return new BsmResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify volume fail:", e);
			return new BsmResult(false, "修改失败", null, null);
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

}
